#pragma once
#include <stdint.h>
#include <stdio.h>

extern uint32_t g_seedX;
extern uint32_t g_seedY;
extern uint32_t g_seedZ;
extern uint32_t g_seedW;
extern uint32_t g_seedV;

inline uint32_t RandomXor32() 
{
	g_seedX^=(g_seedX << 13); g_seedX^=(g_seedX >> 17);
	return (g_seedX^=(g_seedX << 15));
}

inline uint32_t RandomXor64() 
{
	uint32_t t = (g_seedX^(g_seedX << 10)); g_seedX = g_seedY;
	return g_seedY = (g_seedY^(g_seedY >> 10))^(t^(t >> 13));
}

inline  uint32_t RandomXor96() 
{
	uint32_t t = (g_seedX^(g_seedX << 10)); g_seedX = g_seedY; g_seedY = g_seedZ;
	return g_seedZ = (g_seedZ^(g_seedZ >> 26))^(t^(t>>5));
}

inline uint32_t RandomXor128() 
{
	uint32_t t = (g_seedX^(g_seedX << 11));
	g_seedX = g_seedY; g_seedY = g_seedZ; g_seedZ = g_seedW;
	return g_seedW = (g_seedW^(g_seedW >> 19))^(t^(t >> 8));
}

inline uint32_t RandomXor160() 
{
	uint32_t t = (g_seedX^(g_seedX << 2));
	g_seedX = g_seedY; g_seedY = g_seedZ; g_seedZ = g_seedW; g_seedW = g_seedV;
	return g_seedV = (g_seedV^(g_seedV >> 4))^(t^(t >> 1));
}

inline uint32_t RandomXorwow() 
{
	static uint32_t d = 6615241;
	uint32_t t = (g_seedX^(g_seedX>>2));
	g_seedX = g_seedY; g_seedY = g_seedZ; g_seedZ = g_seedW; g_seedW = g_seedV;
	g_seedV = (g_seedV^(g_seedV << 4))^(t^(t << 1));
	return (d+=362437)+g_seedV;
}

inline void RandSeed(uint32_t x) 
{
	g_seedX = x;
}

inline void RandSeed(uint32_t x, uint32_t y) 
{
	g_seedX = x;
	g_seedY = y;
}

inline void RandSeed(uint32_t x, uint32_t y, uint32_t z) 
{
	g_seedX = x;
	g_seedY = y;
	g_seedZ = z;
}

inline void RandSeed(uint32_t x, uint32_t y, uint32_t z, uint32_t w) 
{
	g_seedX = x;
	g_seedY = y;
	g_seedZ = z;
	g_seedW = w;
}

inline void RandSeed(uint32_t x, uint32_t y, uint32_t z, uint32_t w, uint32_t v) 
{
	g_seedX = x;
	g_seedY = y;
	g_seedZ = z;
	g_seedW = w;
	g_seedV = v;
}

inline uint32_t Random() 
{
	return RandomXor160();
}

inline uint32_t Random(uint32_t maxValue) 
{
	uint32_t rate = 0;
	if (maxValue > 0)
	{
		rate = Random() % maxValue;
	}
	return rate;
}

inline bool RandPercent(float rate) 
{
	bool reuslt = false;
	if ((Random(10000) / 100.0f) <= rate)
	{
		reuslt = true;
	}
	return reuslt;
}

inline uint32_t Random(uint32_t minValue, uint32_t maxValue) 
{
    uint32_t rate = 0;
    if (minValue == maxValue) 
	{
        rate = minValue;
    }
    else if (maxValue > minValue) 
	{
        rate = minValue + (Random() % (maxValue - minValue + 1));
    }
    else 
	{
        rate = maxValue + (Random() % (minValue - maxValue + 1));
    }
    return rate;
}

// ��minValue��maxValue����ѡcount����������뵽result���ⲿ�����ڴ�
inline void RandNum32List(uint32_t minValue, uint32_t maxValue, uint32_t* result, uint32_t count)
{
	if (minValue >= maxValue || count == 0)
	{
		return;
	}

	uint32_t num = maxValue - minValue + 1;
	if (num < count)
	{
		count = num;
	}

	if (num == count) 
	{
		for (uint32_t i = 0; i < count; ++i)
		{
			result[i] = minValue + i;
		}
		return;
	}

	uint32_t* arr = new uint32_t[num];

	for (uint32_t i = 0; i < num; ++i)
	{
		arr[i] = minValue + i;
	}

	for (uint32_t i = 0; i < count; ++i)
	{
		uint32_t index = Random() % num;
		result[i] = arr[index];

		arr[index] = arr[num - 1 - i];
		--num;
	}

	delete[] arr;
}

// ��minValue��maxValue����ѡcount����������뵽result���ⲿ�����ڴ� ignoreNum��ʾ���˵�ĳ����
inline void RandNum32List(uint32_t minValue, uint32_t maxValue, uint32_t* result, uint32_t count, uint32_t ignoreNum)
{
	if (minValue >= maxValue || count == 0)
	{
		return;
	}

	uint32_t num = maxValue - minValue + 1;
	if (num < count)
	{
		count = num;
	}

	if (num == count)
	{
		for (uint32_t i = 0; i < count; ++i)
		{
			result[i] = minValue + i;
		}
		return;
	}

	uint32_t newNum = num;

	//����к��Ե�����ô��������1
	if (ignoreNum >= 0 && ignoreNum <= maxValue)
	{
		newNum--;
	}

	uint32_t* arr = new uint32_t[newNum];

	for (uint32_t i = 0, j = 0; i < num; ++i)
	{
		//���˵����Ե���
		if (ignoreNum == minValue + i)
		{
			continue;
		}

		arr[j] = minValue + i;
		j++;
	}

	for (uint32_t i = 0; i < count; ++i)
	{
		uint32_t index = Random() % newNum;
		result[i] = arr[index];

		arr[index] = arr[newNum - 1 - i];
		--newNum;
	}

	delete[] arr;
}
